use std::str::FromStr;

use super::model::Cbor;
use crate::{error::AppErr, server::model::Verify};
use axum::{
    body::Bytes,
    extract::{FromRequest, FromRequestParts, Request},
    http::{request::Parts, HeaderMap},
};
use serde::de::DeserializeOwned;

impl<T: DeserializeOwned, S: Sync + Send> FromRequest<S> for Cbor<T> {
    type Rejection = AppErr;

    async fn from_request(req: Request, state: &S) -> Result<Self, AppErr> {
        let body = Bytes::from_request(req, state)
            .await
            .map_err(|_| AppErr::from_static("from request"))?;
        let value: T =
            serde_cbor::from_slice(&body).map_err(|_| AppErr::from_static("cbor decode fail"))?;
        Ok(Cbor(value))
    }
}

const PUB_USER_NAME: &'static str = "xudehua@@";
const PUB_USER_PWD: &'static str = "xudehua##";

impl <S: Send + Sync> FromRequestParts<S> for Verify {

    type Rejection = AppErr;

    async  fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
        let user_name = get_header_value(&parts.headers, "user_name")?;
        let user_pwd = get_header_value(&parts.headers, "user_pwd")?;
        if (user_name != PUB_USER_NAME) || (user_pwd != PUB_USER_PWD) {
            return Err(AppErr::from_static("密码错误"));
        }
        Ok(Verify)
    }
}

pub fn get_header_value<'a>(header: &'a HeaderMap, name: &str) -> Result<&'a str, AppErr> {
    let value = header.get(name)
    .ok_or(AppErr::from_static("no find header"))?
    .to_str().map_err(|_| AppErr::from_static("to str fail"))?;
    Ok(value)
}

pub fn parse_header_value<T: FromStr>(header: &HeaderMap, name: &str) -> Result<T, AppErr> {
    let value = get_header_value(header, name)?;
    Ok(value.parse().map_err(|_| AppErr::from_static("parse fail"))?)
}


